package main

import (
	"flag"
	"fmt"
	"log"
	"time"

	"mig/pkg/comparer"
	"mig/pkg/data"
	"mig/pkg/migrator"
	"mig/pkg/reader"
	"mig/pkg/types"
	"mig/pkg/utils"
)

var (
	configPath = flag.String("config", "./benchmark/test_migrate/conf/employees_basic.yaml", "path to config file")
	testName   = flag.String("test", "test", "test name")
	outputPath = flag.String("output", "./benchmark/test_migrate/output", "path to output directory")
)

func tryFetchIntegrityInfo(database data.Database, cfg *types.Config) *types.IntegrityInfo {
	rd := reader.NewDefaultReader(database, cfg.ChunkSize, cfg.MaxWorkers)
	tgtInfo, err := rd.Read(cfg.Algorithm)
	if err != nil {
		log.Printf("failed to fetch digest tree: %v", err)
		return nil
	}
	return tgtInfo
}

func prepare(cfg *types.Config, ds, dt data.Database) {
	m := migrator.NewMigrator(cfg.Algorithm, cfg.ChunkSize, cfg.MaxWorkers)
	_, err := m.Migrate(ds, dt, nil)
	if err != nil {
		panic(err)
	}
	log.Printf("prepare finished")
}

func main() {
	flag.Parse()
	cfg := utils.MustLoad[*types.Config](*configPath)
	log.Printf("config path: %v", *configPath)
	fmt.Println(utils.FormatJSONString(cfg))
	ds := data.NewDatabase(cfg, true)
	dt := data.NewDatabase(cfg, false)

	prepare(cfg, ds, dt)

	for _, initSQL := range cfg.TargetDatabase.InitSQL {
		log.Printf("init sql: %v", initSQL)
		if err := dt.Execute(initSQL); err != nil {
			log.Printf("failed to execute init sql: %v", err)
			return
		}
	}

	var (
		unequalChunks []types.UnequalChunk
		srcInfo       *types.IntegrityInfo
		tgtInfo       *types.IntegrityInfo
	)
	srcInfo = tryFetchIntegrityInfo(ds, cfg)
	tgtInfo = tryFetchIntegrityInfo(dt, cfg)

	if !srcInfo.Empty() && !tgtInfo.Empty() {
		result := tgtInfo.Compare(srcInfo)
		fmt.Println("result:")
		result.Print()

		if len(result.UnequalChunks) == 0 {
			log.Printf("No need to migrate")
			return
		}
		unequalChunks = result.UnequalChunks
	}
	log.Printf("unequalChunks: %d", len(unequalChunks))

	var (
		result *types.CompareResult
		err    error
	)
	m := migrator.NewMigrator(cfg.Algorithm, cfg.ChunkSize, cfg.MaxWorkers)
	utils.ReportBenchmarkJSON(*outputPath, *testName+"_migrate", func() {
		_, err = m.Migrate(ds, dt, unequalChunks)
	}, time.Second*1, 1)
	if err != nil {
		log.Printf("failed to migrate: %v", err)
		return
	}

	for _, postMigrateSQL := range cfg.TargetDatabase.PostMigrateSQL {
		if err = dt.Execute(postMigrateSQL); err != nil {
			log.Printf("failed to execute sql: %v", err)
			return
		}
	}

	c := comparer.NewComparer(cfg.Algorithm, cfg.ChunkSize, cfg.MaxWorkers)
	utils.ReportBenchmarkJSON(*outputPath, *testName+"_compare", func() {
		result, err = c.Compare(ds, dt, srcInfo)
	}, time.Second*1, 1)
	if err != nil {
		log.Printf("failed to compare: %v", err)
		return
	}

	result.Print()
}
